﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ComplexNumbers
{
    struct Complex
    {
        double real;
        double imaginary;

        public Complex(double real, double imaginary)
        {
            this.real = real;
            this.imaginary = imaginary;
        }

        public double Real
        {
            get
            {
                return (real);
            }
            set
            {
                real = value;
            }
        }

        public double Imaginary
        {
            get
            {
                return (imaginary);
            }
            set
            {
                imaginary = value;
            }
        }

        public override string ToString()
        {
            return (String.Format("({0}, {1}i)", real, imaginary));
        }

        public static explicit operator double(Complex complex)
        {
            if (complex.imaginary != 0)
                return Double.NaN;
            else
            {
                return (double)complex.Real;
            }
           
        }

        public static implicit operator Complex(double value)
        {
            return new Complex((double)value, 0f);
        }

        public static bool operator ==(Complex c1, Complex c2)
        {
            if ((c1.real == c2.real) &&
            (c1.imaginary == c2.imaginary))
                return (true);
            else
                return (false);
        }

        public static bool operator !=(Complex c1, Complex c2)
        {
            return (!(c1 == c2));
        }

        public override bool Equals(object o2)
        {
            Complex c2 = (Complex)o2;

            return (this == c2);
        }

        public override int GetHashCode()
        {
            return (real.GetHashCode() ^ imaginary.GetHashCode());
        }

        public static Complex operator +(Complex c1, Complex c2)
        {
            return (new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary));
        }

        public static Complex operator -(Complex c1, Complex c2)
        {
            return (new Complex(c1.real - c2.real, c1.imaginary - c2.imaginary));
        }

        // product of two complex numbers
        public static Complex operator *(Complex c1, Complex c2)
        {
            return (new Complex(c1.real * c2.real - c1.imaginary * c2.imaginary,
            c1.real * c2.imaginary + c2.real * c1.imaginary));
        }

        // quotient of two complex numbers
        public static Complex operator /(Complex c1, Complex c2)
        {
            if ((c2.real == 0) && (c2.imaginary == 0))
            {
                throw new DivideByZeroException("Can't divide by zero Complex number");
            }
            double newReal = (c1.real * c2.real + c1.imaginary * c2.imaginary) /
                (c2.real * c2.real + c2.imaginary * c2.imaginary);
            double newImaginary = (c2.real * c1.imaginary - c1.real * c2.imaginary) /
                (c2.real * c2.real + c2.imaginary * c2.imaginary);

            return (new Complex(newReal, newImaginary));
        }

        public double this[int index]
        {
            get
            {
                if ((index >= 0) && (index < 2))
                {
                    if (index == 0)
                        return this.real;
                    else
                        return this.imaginary;
                }
                else
                {
                    throw new IndexOutOfRangeException(String.Format(
                        "Index {0} is invalid!", index));
                }
            }

            set
            {
                if ((index < 0) || (index > 1))
                {
                    throw new IndexOutOfRangeException(String.Format(
                        "Index {0} is invalid!", index));
                }
                if (index == 0)
                {
                    this.real = value;
                }
                else
                {
                    this.imaginary = value;
                }

            }
        }
    }
}
